/* * Sun Public License Notice * * The contents of this file are subject to the Sun Public License * Version 1.0 (the "License"). You may not use this file except in * compliance with the License. A copy of the License is available at * http://www.sun.com/ * * The Original Code is Forte for Java, Community Edition. The Initial * Developer of the Original Code is Sun Microsystems, Inc. Portions * Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved. */ package org.openide.explorer.propertysheet; import java.awt.*; import java.awt.event.*; import java.beans.PropertyEditor; import java.util.Vector; import javax.swing.*; import javax.swing.border.*; import javax.swing.FocusManager; /** * A lightweight component creating a labelled button. * Can be "plastic", which means that when a mouse * enters the button, the area of the button is stubbed. <code>SheetButton</code> can contain one inner component. * * @author Jan Jancura * @version 0.18, May 6, 1997 */ final class SheetButton extends JPanel { /** generated Serialized Version UID */ static final long serialVersionUID = -5681433767155127558L; // variables ................................................................. /** There are all listeners stored. * @associates SheetButtonListener*/ private transient Vector listeners = new Vector (1,5); /** There are action command string stored. */ private String actionCommand = "click"; // NOI18N /** Label of this button. */ private String label; /** Preferred size of this button. */ private Dimension preferredSize = null; /** State of button. */ private boolean pressed = false; /** State of focus. */ private boolean hasFocus = false; /** True if focus is received from mouse. */ private boolean hasFocusFromMouse = false; /** True if button can receive focus. */ private boolean focusTransferable = false; /** True is is in "plastic" mode. */ private boolean isPlastic = false; /** Listens on focus/key/mouse events. */ private InnerListener innerListener; /** SheetButton can contains one inner component. */ private JComponent innerComponent = null; /** Is true if mouseEntered and mouseExited actions should be propagated. */ private boolean plasticNotify = false; /** Foreground color. */ private Color foreground = SystemColor.controlText; /** Inactive foreground color. */ private Color inForeground = SystemColor.textInactiveText; // init ................................................................. /** * Construct a button with empty label. */ public SheetButton () { this ("", false, false); // NOI18N } /** * Construct a button with label and standard appearance (not plastic). * * @param aLabel the label */ public SheetButton (String aLabel) { this (aLabel, false, false); } /** * Construct a button with label. * * @param aLabel the label * @param boolean <code>true</code> if should use plastic appearance */ public SheetButton (String aLabel, boolean isPlasticButton) { this (aLabel, isPlasticButton, false); } /** * Construct a button with label and possibly a plastic listener. * @param label the label * @param isPlasticButton <code>true</code> if should be plastic * @param plasticActionNotify <code>true</code> if mouse enter/exit events should be propagated * */ public SheetButton (String aLabel, boolean isPlasticButton, boolean plasticActionNotify) { setDoubleBuffered (false); setOpaque (true); label = aLabel == null ? "" : aLabel; // NOI18N isPlastic = isPlasticButton; plasticNotify = plasticActionNotify; innerListener = new InnerListener (); addMouseListener (innerListener); addKeyListener (innerListener); } // variables ................................................................. /** * Return whether focus should be traversable. */ public boolean isFocusTraversable () { return focusTransferable; } /** * Set whether focus should be traversable. * @param ft <code>true</code> if so * @see #isFocusTraversable */ public void setFocusTransferable (boolean ft) { if (isFocusTraversable () == ft) return; focusTransferable = ft; if (ft) addFocusListener (innerListener); else removeFocusListener (innerListener); } /** * Sets tooltip test. */ public void setToolTipText (String str) { if (innerComponent != null) innerComponent.setToolTipText (str); super.setToolTipText (str); } /* * @return Standart method returned preferredSize (depends on font size only). */ public Dimension getPreferredSize () { if (preferredSize == null) updatePreferredSize (); return preferredSize == null ? new Dimension (10,10) : preferredSize; } /* * Sets the font of this component. * @param aFont The font to become this component's font. */ public void setFont (Font aFont) { super.setFont (aFont); updatePreferredSize (); } /** * Get the active foreground color. * @return the color */ public Color getActiveForeground () { return foreground; } /** * Set the active foreground color. * @param color the color */ public void setActiveForeground (Color color) { foreground = color; } /** * Get the inactive foreground color. * @return the color */ public Color getInactiveForeground () { return inForeground; } /** * Set the inactive foreground color. * @param color the color */ public void setInactiveForeground (Color color) { inForeground = color; } /* * Gets the label of this button. * @return the button's label. */ public String getLabel () { return label; } /* * Sets the button's label to be the specified string. * @param label the new label. */ public void setLabel (String aLabel) { label = aLabel; updatePreferredSize (); repaint (); } /** * Set whether button should appear stubbed. * @param aPressed <code>true</code> if so */ public void setPressed (boolean aPressed) { if (pressed == aPressed) return; pressed = aPressed; if (pressed) setBorder (new EmptyBorder (2, 2, 0, 0)); else setBorder (new EmptyBorder (1, 1, 1, 1)); repaint (); } /** * Test whether button is pressed. * @return <code>true</code> if so */ public boolean isPressed () { return pressed; } /** * Set whether button is plastic. * @param plastic <code>true</code> if so */ public void setPlastic (boolean plastic) { this.isPlastic = plastic; repaint (); } /** * Test whether button is plastic. * @return <code>true</code> if so */ public boolean isPlastic () { return isPlastic; } /** * Set the action command. * @param command the new command, e.g. <code>"click"</code> */ public void setActionCommand (String command) { actionCommand = command; } /** * Attaches component for this button. */ public Component add (Component innerComponent) { setLayout (new BorderLayout ()); setBorder (new EmptyBorder (1, 1, 1, 1)); add ("Center", innerComponent); // NOI18N removeMouseListener (innerListener); innerComponent.addMouseListener (innerListener); return this.innerComponent = (JComponent) innerComponent; } /** * Recalculates preferred size. */ private void updatePreferredSize () { Graphics g = getGraphics (); if (g == null) return; Font font = null; if ((font = getFont ()) == null) return; FontMetrics fontMetrics = g.getFontMetrics (font); preferredSize = new Dimension ( fontMetrics.stringWidth (label) + 10, fontMetrics.getHeight () + 6 ); } /** * Standart methods painting SheetButton. */ public void paint (Graphics g) { super.paint (g); Dimension size = getSize (); Color color = g.getColor (); Font theFont = g.getFont (); g.setFont (getFont ()); FontMetrics fontMetrics = g.getFontMetrics (); if (pressed || hasFocus) { if (innerComponent == null) { g.setColor (isEnabled () ? getActiveForeground () : getInactiveForeground ()); g.drawString ( label, 6, (size.height - fontMetrics.getHeight ()) / 2 + 1 + fontMetrics.getMaxAscent () ); } } else { g.setColor (SystemColor.controlLtHighlight); g.drawLine (0, 0, size.width - 1, 0); g.drawLine (0, 0, 0, size.height - 1); g.setColor (SystemColor.controlDkShadow); g.drawLine (size.width - 1, 0, size.width - 1, size.height - 1); g.drawLine (0, size.height - 1, size.width - 1, size.height - 1); if (innerComponent == null) { g.setColor (isEnabled () ? getActiveForeground () : getInactiveForeground ()); g.drawString ( label, 5, (size.height - fontMetrics.getHeight ()) / 2 + fontMetrics.getMaxAscent () ); } } g.setFont (theFont); g.setColor (color); } /* * Returns string representation of this class. * @return <CODE>String</CODE> Representation of this class. */ public String toString () { return getClass ().getName () + "[ \"" + label + "\" ]"; // NOI18N } // SheetButtonListener support ...................................................... /** * Adds Listener. */ void addSheetButtonListener (SheetButtonListener sheetButtonListener) { listeners.addElement (sheetButtonListener); } /** * Removes Listener. */ void removeSheetButtonListener (SheetButtonListener sheetButtonListener) { listeners.removeElement (sheetButtonListener); } public void notifySheetButtonListenersAboutClick (ActionEvent e) { Vector l = (Vector) listeners.clone (); int i, k = l.size (); for (i = 0; i < k; i++) ((SheetButtonListener) l.elementAt (i)).sheetButtonClicked (e); } public void notifySheetButtonListenersAboutEntered (ActionEvent e) { Vector l = (Vector) listeners.clone (); int i, k = l.size (); for (i = 0; i < k; i++) ((SheetButtonListener) l.elementAt (i)).sheetButtonEntered (e); } public void notifySheetButtonListenersAboutExited (ActionEvent e) { Vector l = (Vector) listeners.clone (); int i, k = l.size (); for (i = 0; i < k; i++) ((SheetButtonListener) l.elementAt (i)).sheetButtonExited (e); } // innerclasses .......................................................................... private class InnerListener extends MouseMotionAdapter implements MouseListener, KeyListener, FocusListener { /* * Standart helper method. */ public void mouseClicked (MouseEvent e) { } /* * Standart helper method. */ public void mousePressed (MouseEvent e) { if (isFocusTraversable ()) { hasFocusFromMouse = true; requestFocus (); } if (!isPlastic) { pressed = true; setBorder (new EmptyBorder (2, 2, 0, 0)); notifySheetButtonListenersAboutEntered ( new ActionEvent ( SheetButton.this, ActionEvent.ACTION_FIRST, actionCommand ) ); if (innerComponent != null) { // setBorder (new EmptyBorder (2, 2, 0, 0)); invalidate (); getParent ().validate (); innerComponent.addMouseMotionListener (innerListener); } else addMouseMotionListener (innerListener); repaint (); } } /* * Standart helper method. */ public void mouseReleased (MouseEvent e) { if (!isPlastic) { if (innerComponent != null) { innerComponent.removeMouseMotionListener (innerListener); // setBorder (new EmptyBorder (1, 1, 1, 1)); invalidate (); getParent ().validate (); } else removeMouseMotionListener (innerListener); repaint (); if (isEnabled () && pressed) { notifySheetButtonListenersAboutClick ( new ActionEvent ( SheetButton.this, ((e.getClickCount () % 2) == 1) ? (ActionEvent.ACTION_FIRST + 1) : ActionEvent.ACTION_FIRST, actionCommand ) ); notifySheetButtonListenersAboutExited ( new ActionEvent ( SheetButton.this, ActionEvent.ACTION_FIRST, actionCommand ) ); } pressed = false; setBorder (new EmptyBorder (1, 1, 1, 1)); } else { if (isEnabled ()) notifySheetButtonListenersAboutClick ( new ActionEvent ( SheetButton.this, ActionEvent.ACTION_FIRST, actionCommand ) ); } } /* * Standart helper method. */ public void mouseEntered (MouseEvent e) { if (isPlastic) { pressed = true; setBorder (new EmptyBorder (2, 2, 0, 0)); repaint (); if (plasticNotify) notifySheetButtonListenersAboutEntered ( new ActionEvent ( SheetButton.this, ActionEvent.ACTION_FIRST, actionCommand ) ); } } /* * Standart helper method. */ public void mouseExited (MouseEvent e) { if (isPlastic) { pressed = false; setBorder (new EmptyBorder (1, 1, 1, 1)); repaint (); if (plasticNotify) notifySheetButtonListenersAboutExited ( new ActionEvent ( SheetButton.this, ActionEvent.ACTION_FIRST, actionCommand ) ); } } public void mouseDragged (MouseEvent e) { if (new Rectangle ( SheetButton.this.getSize () ).contains (e.getPoint ()) == pressed ) return; if (pressed) notifySheetButtonListenersAboutExited ( new ActionEvent ( SheetButton.this, ActionEvent.ACTION_FIRST, actionCommand )); else notifySheetButtonListenersAboutEntered ( new ActionEvent ( SheetButton.this, ActionEvent.ACTION_FIRST, actionCommand )); pressed = !pressed; if (pressed) setBorder (new EmptyBorder (2, 2, 0, 0)); else setBorder (new EmptyBorder (1, 1, 1, 1)); if (innerComponent != null) { invalidate (); getParent ().validate (); } repaint (); } public void keyTyped (KeyEvent e) { if ((e.getKeyChar () == ' ') || (e.getKeyChar () == '\n')) notifySheetButtonListenersAboutClick ( new ActionEvent ( SheetButton.this, ActionEvent.ACTION_FIRST + 1, actionCommand ) ); } public void keyPressed (KeyEvent e) { if (e.getKeyCode () == KeyEvent.VK_DOWN) { FocusManager fm = FocusManager.getCurrentManager (); fm.focusNextComponent (SheetButton.this); } else if (e.getKeyCode () == KeyEvent.VK_UP) { FocusManager fm = FocusManager.getCurrentManager (); fm.focusPreviousComponent (SheetButton.this); } } public void keyReleased (KeyEvent e) { } public void focusGained (FocusEvent fe) { if (hasFocusFromMouse) hasFocusFromMouse = false; else hasFocus = true; notifySheetButtonListenersAboutEntered ( new ActionEvent ( SheetButton.this, ActionEvent.ACTION_FIRST + 1, actionCommand ) ); repaint (); } public void focusLost (FocusEvent fe) { hasFocus = false; notifySheetButtonListenersAboutExited ( new ActionEvent ( SheetButton.this, ActionEvent.ACTION_FIRST + 1, actionCommand ) ); repaint (); } } } /* * Log * 8 Gandalf 1.7 1/19/00 Jan Jancura Cycling while repainting * solved. * 7 Gandalf 1.6 1/17/00 Jan Jancura Button Updated * 6 Gandalf 1.5 1/12/00 Ian Formanek NOI18N * 5 Gandalf 1.4 10/22/99 Ian Formanek NO SEMANTIC CHANGE - Sun * Microsystems Copyright in File Comment * 4 Gandalf 1.3 9/15/99 Jaroslav Tulach More private things & * support for default property. * 3 Gandalf 1.2 6/8/99 Ian Formanek ---- Package Change To * org.openide ---- * 2 Gandalf 1.1 3/20/99 Jesse Glick [JavaDoc] * 1 Gandalf 1.0 1/5/99 Ian Formanek * $ */